# ssh远程执行命令程序

import socket
import subprocess
import struct

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind(("127.0.0.1", 8080))
server.listen(5)  # 5代表最大挂起的连接数

print("ssh starting...")
while True:  # 链接循环
    # 建立链接
    conn, client_addr = server.accept()
    print(f"[client_addr]: {client_addr}")
    # 进行通讯
    while True:  # 通信循环
        try:  # 针对Windows系统，接收空字符串的处理方法
            # 1. 接收命令
            cmd = conn.recv(8096)  # Windows系统会在这里抛出错误
            # 客户端不允许发送空字符串
            if not cmd:  # 针对linux系统，接收空字符串的处理方法
                break
            print(f"[client data] : {cmd.decode('utf-8')}")
            # 2. 执行命令，拿到结果
            # 获取结果并拿到结果
            obj = subprocess.Popen(
                cmd.decode('utf-8'),  # 执行的命令
                shell=True,  # 使用shell执行
                stdout=subprocess.PIPE,  # 设置正确返回值的管道,对应: obj.stdout.read().decode("gbk")
                stderr=subprocess.PIPE  # 设置错误值的管道,对应: obj.stderr.read().decode("gbk")
            )

            # windows 默认 gbk
            # linux   默认 utf-8
            stdout = obj.stdout.read()
            stderr = obj.stderr.read()

            # 3. 返回执行结果
            # 第1步: 制作固定长的报头
            total_size = len(stdout) + len(stderr)
            header = struct.pack('i', total_size)
            # 第2步: 发送报头
            conn.send(header)
            # 第3步: 发送数据
            conn.send(stdout)
            conn.send(stderr)
        except ConnectionResetError:
            break

    # 6. 挂电话
    conn.close()

# 7. 关机
server.close()
